package com.sky.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.OperationConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.dto.SetmealDishDTO;
import com.sky.dto.mapper.DishDTOMapper;
import com.sky.entity.Category;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.entity.Setmeal;
import com.sky.exception.*;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.*;

/**
 * @author luo20
 * @description 针对表【dish(菜品)】的数据库操作Service实现
 * @createDate 2025-07-06 16:37:09
 */
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish>
        implements DishService {
    private static final String OPERATION_INSERT = "INSERT";
    private static final String OPERATION_UPDATE = "UPDATE";


    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private DishDTOMapper dishDTOMapper;
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private CategoryMapper categoryMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer save(DishDTO dishDTO) {
        // 判断分类状态是否禁用
        judgmentCategoryStatus(dishDTO,OPERATION_INSERT);
        // 对象转换
        Dish dish = dishDTOMapper.toDish(dishDTO);
        // 把DishDTO转换成集合
        List<DishFlavor> dishFlavorList = dishDTO.getFlavors();
        // 新增菜品功能
        Integer result = dishMapper.save(dish);
        log.info("dishId:{}", dish.getId());
        // 判断菜品口味列表是否为空
        Integer dishFlavorResult = 0;
        if (CollectionUtils.isNotEmpty(dishFlavorList)) {
            // 为dishFlavorList设置dishId
            dishFlavorList.forEach(dishFlavor -> dishFlavor.setDishId(dish.getId()));
            // 不为空实现批量插入
            dishFlavorResult = dishFlavorMapper.saveBatch(dishFlavorList);
            // 判断菜品口味插入是否成功
            if (dishFlavorResult < 0) {
                throw new RuntimeException("批量插入菜品口味失败");
            }
        }
        // 返回菜品插入结果
        return result;
    }

    // 判断分类状态是否禁用
    private void judgmentCategoryStatus(DishDTO dishDTO,String operationType) {
        // 根据插入和修改操作类型判断返回提示语
        String finalMessage;
        if (operationType.equals(OperationConstant.INSERT)){
            finalMessage = MessageConstant.CATEGORY_UNDER_NO_ADD_DISHES;
        }else{
            finalMessage = MessageConstant.CATEGORY_UNDER_NO_UPDATE_DISHES;
        }
        Category category = categoryMapper.selectById(dishDTO.getCategoryId());
        if (category == null || Objects.equals(category.getStatus(), StatusConstant.DISABLE)) {
            throw new AddOrUpdateDishFailException(finalMessage);
        }
    }

    @Override
    public PageResult<DishVO> pageDish(DishPageQueryDTO dishPageQueryDTO) {
        // 开启分页
        PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
        // 封装条件到map中
        Map<String, Object> map = new HashMap<>();
        map.put("name", dishPageQueryDTO.getName());
        map.put("status", dishPageQueryDTO.getStatus());
        map.put("categoryId", dishPageQueryDTO.getCategoryId());
        // 获取菜品数据
        List<DishVO> dishList = dishMapper.selectByConditions(map);
        log.info("查询到的菜品数据为：{}", dishList);
        // 封装分页结果
        Page<DishVO> dishPage = (Page<DishVO>) dishList;
        // 返回结果
        return PageResult.<DishVO>builder()
                .total(dishPage.getTotal())
                .records(dishPage.getResult())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer startOrStop(Integer status, Long id) {
        // 如果是启用操作，需要检查所属分类状态
        if (Objects.equals(status, StatusConstant.ENABLE)) {
            // 先查询菜品信息获取分类ID
            Dish dish = dishMapper.selectById(id);
            if (dish != null) {
                // 查询分类状态
                Category category = categoryMapper.selectById(dish.getCategoryId());
                if (category == null || !Objects.equals(category.getStatus(), StatusConstant.ENABLE)) {
                    throw new DishUpdateErrorException(MessageConstant.DISH_CATEGORY_DISABLED);
                }
            }
        }
        // 转成dish实体
        Dish dish = new Dish()
                .setId(id)
                .setStatus(status);
        Integer dishResult = dishMapper.updStartOrStop(dish);
        // 如果执行停售操作，则包含此菜品的套餐也需要停售。
        if (Objects.equals(status, StatusConstant.DISABLE)) {
            // 查询有多少个套餐关联此菜品 取套餐的id和status进行查询
            List<SetmealDishDTO> setmealDishDTOList = setmealDishMapper.getSetmealByConditions(new Dish()
                    .setId(id)
                    .setStatus(StatusConstant.ENABLE));
            // 如果套餐与菜品有关的套餐数量大于0
            if (CollectionUtils.isNotEmpty(setmealDishDTOList)) {
                // 停售跟菜品有关联的套餐
                setmealDishDTOList.forEach(s -> {
                    Setmeal setmeal = new Setmeal()
                            .setId(s.getSetmealId())
                            .setStatus(status);
                    Integer setMealResult = setmealMapper.updSetmealStatusById(setmeal);
                    if (setMealResult < 0) {
                        throw new UpdateStatusErrorException(MessageConstant.UPDATE_SETMEAL_STATUS_FAILED);
                    }
                });
            }
        }
        return dishResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DishDTO dishDTO) {
        // 判断分类状态是否禁用
        judgmentCategoryStatus(dishDTO,OPERATION_UPDATE);
        // 1.将DTO转换成entity
        Dish dish = dishDTOMapper.toDish(dishDTO);
        List<DishFlavor> flavors = dishDTO.getFlavors();
        // 2.根据菜品id更新菜品功能
        Integer dishResult = dishMapper.updDishById(dish);
        // 判断是否更新成功 成功后删除菜品的口味数据 否则报错
        if (dishResult <= 0) {
            throw new DishUpdateErrorException(MessageConstant.UPDATE_DISH_FAILD);
        }
        // 3.根据菜品id查询是否有菜品口味数据 有就删除
        // 获取dishId
        Long dishId = dish.getId();
        List<DishFlavor> dishFlavors = dishFlavorMapper.getDishFlavorByDishId(dishId);
        if (CollectionUtils.isNotEmpty(dishFlavors)) {
            // dishId转成list类型
            // 4.删除原本菜品的口味数据
            Long delFlavorResult = dishFlavorMapper.delFlavorByDishIds(List.of(dishId));
            if (delFlavorResult <= 0) {
                throw new DishFlavorDeleteErrorException(MessageConstant.DISH_FLAVOR_DELETE_ERROR);
            }
        }
        // 5.判断传来的菜品口味数据是否为空
        if (CollectionUtils.isNotEmpty(flavors)) {
            // 为新的菜品口味数据绑定菜品id
            flavors.forEach(flavor -> flavor.setDishId(dishId));
            // 6.不为空，则添加新的菜品口味数据
            Integer addFlavorResult = dishFlavorMapper.saveBatch(flavors);
            if (addFlavorResult <= 0) {
                throw new DishFlavorAddErrorException(MessageConstant.DISH_FLAVOR_ADD_ERROR);
            }
        }

    }

    @Override
    public DishVO getByIdWithFlavor(Long id) {
        return dishMapper.getDishByIdWithFlavor(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByDishIds(List<Long> ids) {
        // 判断菜品id是否为空
        if (CollectionUtils.isEmpty(ids)) {
            throw new DishIdsEmptyException(MessageConstant.DISH_ID_NOT_FOUND);
        }
        // 1. 查出所有要删的菜品
        List<Dish> dishList = dishMapper.selectByDishIds(ids);
        if (CollectionUtils.isEmpty(dishList)) {
            throw new DeletionNotAllowedException(MessageConstant.DISH_NOT_FOUND);
        }
        // 2. 检查是否有启售菜品
        dishList.forEach(dish -> {
            // 有就报起售中的菜品不能删除
            if (Objects.equals(dish.getStatus(), StatusConstant.ENABLE)) {
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        });
        // 3.根据菜品ids查询菜品关联的套餐
        List<Long> dishIdList = dishList.stream().map(Dish::getId).toList();
        List<SetmealDishDTO> setmealList = setmealDishMapper.getSetmealsByDishIds(dishIdList);
        // 4.有就报当前菜品关联了套餐,不能删除
        if (CollectionUtils.isNotEmpty(setmealList)) {
            // 获取套餐名称
            List<String> setmealNameList = setmealList.stream().map(SetmealDishDTO::getSetmealName).toList();
            // 拼接套餐名称
            String setmealNames = StringUtils.join(setmealNameList, ",");
            // 当前菜品关联了套餐,不能删除
            throw new DeletionNotAllowedException(MessageFormat.format(MessageConstant.DISH_BE_RELATED_BY_SETMEAL_WITH_NAMES,setmealNames));
        }
        // 根据菜品ids批量查询菜品口是否存在
        Integer flavorCount = dishFlavorMapper.getFlavorCountByDishIds(ids);
        // 存在就删
        if (flavorCount > 0) {
            // 批量删口味
            Long delFlavorResult = dishFlavorMapper.delFlavorByDishIds(ids);
            if (delFlavorResult <= 0) {
                throw new DishFlavorDeleteErrorException(MessageConstant.DISH_FLAVOR_DELETE_ERROR);
            }
        }
        // 4. 批量删菜品
        Integer deleteResult = dishMapper.deleteByDishIds(ids);
        if (deleteResult <= 0) {
            throw new DishDeleteErrorException(MessageConstant.DISH_DELETE_FAILD);
        }
        return deleteResult == ids.size();
    }

    @Override
    public List<DishVO> getDishWithFlavorsByCategoryId(Long categoryId) {
        HashMap<String,Object> map = new HashMap<>();
        map.put("categoryId",categoryId);
        map.put("status", StatusConstant.ENABLE);
        return dishMapper.getDishWithFlavorsByCategoryId(map);
    }

}




